#include "stdafx.h"
#include "wf_polylinesegment.h"
#include "pf_polyline.h"
#include "pf_snapper.h"



WF_PolylineSegment::WF_PolylineSegment(PF_Container& container,
        PF_GraphicView& graphicView)
        :PF_PreviewActionInterface("Create Polyline Existing from Segments",
                           container, graphicView) {}


QAction* WF_PolylineSegment::createGUIAction(LX_Define::ActionType /*type*/, QObject* /*parent*/) {
    QAction* action = new QAction(tr("Create Polyline from Existing &Segments"), NULL);
	action->setShortcut(QKeySequence());
    action->setStatusTip(tr("Create Polyline from Existing Segments"));
    return action;
}

void WF_PolylineSegment::init(int status) {
    PF_ActionInterface::init(status);
    targetEntity = NULL;
}

/**
 * Rearranges the atomic entities in this container in a way that connected
 * entities are stored in the right order and direction.
 * Non-recoursive. Only affects atomic entities in this container.
 * 
 * @retval true all contours were closed
 * @retval false at least one contour is not closed
 */
bool WF_PolylineSegment::convertPolyline(PF_Entity* selectedEntity) {

	PF_DEBUG->print("PF_ActionPolylineSegment::convertPolyline");

	PF_Vector current(false);
	PF_Vector start(false);
	PF_Vector end(false);
	PF_Container tmp;

	bool closed = true;

	int pos = container->findEntity(selectedEntity);
	PF_Entity* e1=container->entityAt(pos);

	if (document!=NULL) {
		document->startUndoCycle();
	}
	if (document!=NULL) {
		if (e1!=NULL && e1->isEdge() && !e1->isContainer() &&
					!e1->isProcessed()) {

			PF_AtomicEntity* ce = (PF_AtomicEntity*)e1;

///////////////////////////////////////////////////
			ce->setUndoState(true);
			document->addUndoable(ce);
///////////////////////////////////////////////////

			// next contour start:
			ce->setProcessed(true);
			tmp.addEntity(ce->clone());
			current = ce->getStartpoint();
			end = ce->getEndpoint();

			// find first connected entities:
			for (int ei=pos-1; ei>=0; --ei) {
				PF_Entity* e2=container->entityAt(ei);

				if (e2!=NULL && e2->isEdge() && !e2->isContainer() &&
						!e2->isProcessed()) {

					PF_AtomicEntity* e = (PF_AtomicEntity*)e2;
///////////////////////////////////////////////////
					e->setUndoState(true);
					document->addUndoable(e);
///////////////////////////////////////////////////
					if (e->getEndpoint().distanceTo(current) <
							1.0e-4) {
						e->setProcessed(true);
						tmp.insertEntity(0,e->clone());
						current = e->getStartpoint();
					} else if (e->getStartpoint().distanceTo(current) <
							   1.0e-4) {
						e->setProcessed(true);
						PF_AtomicEntity* cl = (PF_AtomicEntity*)e->clone();
						cl->reverse();
						tmp.insertEntity(0,cl);
						current = cl->getStartpoint();
					}else
						break;
				}
			}

			if (current.distanceTo(end)>1.0e-4) {
				closed = false;
			}

			current = ce->getEndpoint();
			start = ce->getStartpoint();
			// find last connected entities:
			for (uint ei=pos+1; ei<container->count(); ++ei) {
				PF_Entity* e2=container->entityAt(ei);
///////////////////////////////////////////////////
				e2->setUndoState(true);
				document->addUndoable(e2);
///////////////////////////////////////////////////
				if (e2!=NULL && e2->isEdge() && !e2->isContainer() &&
						!e2->isProcessed()) {
					PF_AtomicEntity* e = (PF_AtomicEntity*)e2;
					if (e->getStartpoint().distanceTo(current) <
							1.0e-4) {
						e->setProcessed(true);
						tmp.addEntity(e->clone());
						current = e->getEndpoint();
					} else if (e->getEndpoint().distanceTo(current) <
							   1.0e-4) {
						e->setProcessed(true);
						PF_AtomicEntity* cl = (PF_AtomicEntity*)e->clone();
						cl->reverse();
						tmp.addEntity(cl);
						current = cl->getEndpoint();
					}else
						break;
				}
			}
			if (current.distanceTo(start)>1.0e-4) {
				closed = false;
			}
		}
	}
	if (document!=NULL) {
		document->endUndoCycle();
	}

	PF_Polyline* newPolyline = new PF_Polyline(container, PF_PolylineAttribute(PF_Vector(false), PF_Vector(false), closed));
	newPolyline->setLayerToActive();
	newPolyline->setPenToActive();
	// add new polyline:
	bool first = true;
	PF_Entity* lastEntity = tmp.lastEntity();
	for (PF_Entity* en=tmp.firstEntity(); en!=NULL; en=tmp.nextEntity()) {
		en->setProcessed(false);
		double bulge = 0.0;
		if (en->rtti()==LX_Define::EntityArc) {
			bulge = ((PF_Arc*)en)->getBulge();
		} else {
			bulge = 0.0;
		}
		if (first) {
			newPolyline->setNextBulge(bulge);
			newPolyline->addVertex(((PF_AtomicEntity*)en)->getStartpoint());
			first = false;
		}
		if (en!=lastEntity || closed==false){
			newPolyline->setNextBulge(bulge);
			newPolyline->addVertex(((PF_AtomicEntity*)en)->getEndpoint());
		}
	}
	double bulge = lastEntity->rtti() == LX_Define::EntityArc? ((PF_Arc*)lastEntity)->getBulge():0.0;
	newPolyline->setNextBulge(bulge);
	newPolyline->endPolyline();
	container->addEntity(newPolyline);

	if (graphicView!=NULL) {
		graphicView->drawEntity(newPolyline);
	}

	if (document!=NULL) {
		document->startUndoCycle();
		document->addUndoable(newPolyline);
		document->endUndoCycle();
	}
	PF_DEBUG->print("PF_ActionPolylineSegment::convertPolyline: OK");
	return closed;
}

void WF_PolylineSegment::trigger() {

    PF_DEBUG->print("PF_ActionPolylineSegment::trigger()");

	if (targetEntity!=NULL /*&& selectedSegment!=NULL && targetPoint.valid */) {
        targetEntity->setHighlighted(false);
        graphicView->drawEntity(targetEntity);
		container->optimizeContours();
		convertPolyline(targetEntity);

        targetEntity = NULL;
        setStatus(ChooseEntity);

        PF_DIALOGFACTORY->updateSelectionWidget(container->countSelected());
    }
////////////////////////////////////////2006/06/15
		graphicView->redraw();
////////////////////////////////////////
}



void WF_PolylineSegment::mouseMoveEvent(PF_MouseEvent* e) {
    PF_DEBUG->print("PF_ActionPolylineSegment::mouseMoveEvent begin");

    switch (getStatus()) {
    case ChooseEntity:
        snapPoint(e);
        break;
    default:
        break;
    }


    PF_DEBUG->print("PF_ActionPolylineSegment::mouseMoveEvent end");
}



void WF_PolylineSegment::mouseReleaseEvent(PF_MouseEvent* e) {
    if (e->button()==Qt::LeftButton) {
        switch (getStatus()) {
        case ChooseEntity:
            targetEntity = catchEntity(e);
            if (targetEntity==NULL) {
                PF_DIALOGFACTORY->commandMessage(tr("No Entity found."));
            } else if (targetEntity->rtti()!=LX_Define::EntityLine && targetEntity->rtti()!=LX_Define::EntityArc) {
                PF_DIALOGFACTORY->commandMessage(
                    tr("Entity must be a line or arc."));
            } else {
                targetEntity->setHighlighted(true);
                graphicView->drawEntity(targetEntity);
//                setStatus(SetReferencePoint);
////////////////////////////////////////2006/06/15
				graphicView->redraw();
////////////////////////////////////////
            	trigger();
            }
            break;
        default:
            break;
        }
    } else if (e->button()==Qt::RightButton) {
        deleteSnapper();
        if (targetEntity!=NULL) {
            targetEntity->setHighlighted(false);
            graphicView->drawEntity(targetEntity);
////////////////////////////////////////2006/06/15
		graphicView->redraw();
////////////////////////////////////////
        }
        init(getStatus()-1);
    }
/*    if (e->button())==Qt::LeftButton) {
        PF_CoordinateEvent ce(snapPoint(e));
        coordinateEvent(&ce);
    } else if (LX_Define::qtToRsButtonState(e->button())==LX_Define::RightButton) {
        deletePreview();
        deleteSnapper
        init(getStatus()-1);
    }
*/
}

void WF_PolylineSegment::updateMouseButtonHints() {
    switch (getStatus()) {
    case ChooseEntity:
        PF_DIALOGFACTORY->updateMouseWidget(tr("Choose one of the segments on the original polyline"),
                                            tr("Cancel"));
        break;
    default:
        PF_DIALOGFACTORY->updateMouseWidget("", "");
        break;
    }
}



void WF_PolylineSegment::updateMouseCursor() {
    graphicView->setMouseCursor(LX_Define::CadCursor);
}



void WF_PolylineSegment::updateToolBar() {
    switch (getStatus()) {
    case ChooseEntity:
        PF_DIALOGFACTORY->requestToolBar(LX_Define::ToolBarSnap);
        break;
    default:
        PF_DIALOGFACTORY->requestToolBar(LX_Define::ToolBarPolylines);
        break;
    }
}


// EOF
